package fetzu.app;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.TimeZone;
import java.util.prefs.Preferences;

import javax.swing.JOptionPane;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import net.oauth.OAuthAccessor;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;

import org.jdesktop.application.Application;
import org.jdesktop.application.Task;
import org.xml.sax.InputSource;

public class FireEagleService {

	static class Response {
		private InputStream source;
		private final String xpathForTimezone = "//@timezone";

		public Response(InputStream source) {
			this.source = source;
		}

		public Response(OAuthMessage result) throws IOException {
			this(result.getBodyAsStream());
		}

		public TimeZone getTimezone() {
			XPath xpath = XPathFactory.newInstance().newXPath();
			InputSource inputSource = new InputSource(source);
			try {
				String result = xpath.evaluate(xpathForTimezone, inputSource);
				TimeZone tz = TimeZone.getTimeZone(result);
				return tz;
			} catch (XPathExpressionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
	}

	static final String FIREEAGLE_API_USER = "https://fireeagle.yahooapis.com/api/0.1/user";

	boolean fireEagleWorking = false;

	final Preferences prefs = Preferences.systemRoot().node("/fetzu/fireeagle");

	private PreferencesConsumer consumer;

	public FireEagleService() {
		try {
			consumer = new PreferencesConsumer("fireeagle", prefs);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			throw new RuntimeException(e1);
		}

		try {
			isAuthenticated = consumer.isAuthenticated();
		} catch (OAuthException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	TimeZone checkResult(OAuthMessage result) throws IOException {
		FireEagleService.Response fer = new FireEagleService.Response(result);

		fireEagleWorking = true;

		return fer.getTimezone();
	}

	private boolean isAuthenticated;

	public boolean isAuthenticated() {
		return isAuthenticated;
	}

	TimeZone queryFireEagle() throws IOException, OAuthException,
			URISyntaxException {
		isAuthenticated = consumer.isAuthenticated();
		if (!isAuthenticated)
			throw new IllegalStateException("not yet authenticated");

		try {
			OAuthAccessor accessor = consumer.newAccessor();
			OAuthMessage result = PreferencesConsumer.CLIENT.invoke(accessor,
					FireEagleService.FIREEAGLE_API_USER, null);
			return checkResult(result);
		} catch (OAuthProblemException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.err.println("deleting OAuth tokens due to exception " + e);
			consumer.removeAccessors();
			fireEagleWorking = false;
		}
		return null;
	}

	public class QueryTimeZoneTask extends Task<TimeZone, Void> {

		public QueryTimeZoneTask(Application application) {
			super(application);
		}

		@Override
		protected TimeZone doInBackground() throws Exception {
			TimeZone result = queryFireEagle();
			return result;
		}
	}

	public class AuthenticateTask extends Task<Void, Void> {

		public AuthenticateTask(Application application) {
			super(application);
		}

		@Override
		protected Void doInBackground() throws Exception {
			OAuthAccessor accessor = consumer.newAccessor();
			String accessAuthorizationUrl = consumer
					.getAccessAuthorizationUrl(accessor);
			BareBonesBrowserLaunch.openURL(accessAuthorizationUrl);
			int confirmation = JOptionPane
					.showConfirmDialog(
							null,
							"Your authorization is needed in your web browser.\nWhen that is complete, click this OK button.",
							"Authorize access to Fire Eagle",
							JOptionPane.OK_CANCEL_OPTION);
			if (confirmation == JOptionPane.OK_OPTION)
				consumer.refreshAccessToken(accessor);
			return null;
		}
	}

}
